package com.zzyl.nursing.service.impl;

import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.sql.ast.SQLExprComparor;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.nursing.config.WebSocketServer;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.nursing.vo.AlertNotifyVo;
import com.zzyl.system.mapper.SysUserRoleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.service.IAlertRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import static java.lang.Double.compare;

/**
 * 报警规则Service业务层处理
 *
 * @author alexis
 * @date 2025-01-15
 */
@Service
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService {
    @Autowired
    private AlertRuleMapper alertRuleMapper;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private IAlertDataService alertDataService;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private SysUserRoleMapper userRoleMapper;
    @Autowired
    private WebSocketServer webSocketServer;

    ;

    /**
     * 查询报警规则
     *
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id) {
        return alertRuleMapper.selectById(id);
    }

    /**
     * 查询报警规则列表
     *
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule) {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule) {
        return alertRuleMapper.insert(alertRule);
    }

    /**
     * 修改报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule) {
        return alertRuleMapper.updateById(alertRule);
    }

    /**
     * 批量删除报警规则
     *
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids) {
        return alertRuleMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除报警规则信息
     *
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id) {
        return alertRuleMapper.deleteById(id);
    }

    @Override
    public void alertFilter() {
        long count = count(Wrappers.lambdaQuery(AlertRule.class).eq(AlertRule::getStatus, 1));
        if (count == 0) {
            return;
        }
        List values = redisTemplate.opsForHash().values(Constants.IOT_DEVICE_LAST_DATA);
        if (ObjectUtil.isNull(values)) {
            return;
        }
        values.forEach(o -> {
            if (ObjectUtil.isNull(o)) {
                return;
            }
            List<DeviceData> deviceDataList = (List<DeviceData>) o;
            deviceDataList.forEach(deviceData -> {
                alterRule(deviceData);
            });
        });


    }

    public void alterRule(DeviceData deviceData) {
        List<AlertRule> rules = list(Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getStatus, 1).eq(AlertRule::getFunctionId, deviceData.getFunctionId()).eq(AlertRule::getProductKey, deviceData.getProductKey()));
        if (ObjectUtil.isNull(rules)) {
            return;
        }
        rules.forEach(rule -> {
            String activeTime = rule.getAlertEffectivePeriod();
            String[] split = activeTime.split("~");
            LocalTime startTime = LocalTime.parse(split[0]);
            LocalTime endTime = LocalTime.parse(split[1]);
            LocalTime time = LocalDateTimeUtil.of(deviceData.getAlarmTime()).toLocalTime();
            if (time.isBefore(startTime) || time.isAfter(endTime)) {
                return;
            }
            Double value = rule.getValue();
            String operator = rule.getOperator();
            Double dataValue = Double.valueOf(deviceData.getDataValue());
            int compare = compare(dataValue, value);
            String silentKey = "chenmozhouqi" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + rule.getId();
            String alertCountKey = "chenmozhouqi" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + rule.getId();
            //判断不符合阈值就退出方法
            if (Objects.equals(operator, ">") && compare <= 0) {
                return;
            } else if (Objects.equals(operator, "<") && compare >= 0) {
                return;
            } else if (Objects.equals(operator, "=") && compare != 0) {
                return;
            }
            Object o = redisTemplate.opsForValue().get(silentKey);
            if (ObjectUtil.isNotNull(o)) {
                return;
            }
            String altercount = (String) redisTemplate.opsForValue().get(alertCountKey);
            if (ObjectUtil.isNull(altercount)) {
                altercount = "1";
                redisTemplate.opsForValue().set(alertCountKey, altercount);
            } else {
                int count = Integer.valueOf(altercount);
                count++;
                if (!(count == rule.getDuration())) {
                    redisTemplate.opsForValue().set(alertCountKey, String.valueOf(count));
                }

            }

            redisTemplate.delete(alertCountKey);
            redisTemplate.opsForValue().set(silentKey, "1", rule.getAlertSilentPeriod(), TimeUnit.MINUTES);
            beachSave(rule, deviceData);

        });
    }

    private void beachSave(AlertRule rule, DeviceData deviceData) {
        List<Long> userIds = new ArrayList<>();
        if (rule.getAlertDataType().equals(0)) {
            if (deviceData.getLocationType().equals(0)) {
                userIds = deviceMapper.selectNursingIdsByIotIdWithElder(deviceData.getIotId());
            } else if (deviceData.getLocationType().equals(1) && deviceData.getPhysicalLocationType().equals(2)) {
                userIds = deviceMapper.selectNursingIdsByIotIdWithBed(deviceData.getIotId());
            }
        } else {
            userIds = userRoleMapper.selectUserIdByRoleName("维修工");
        }
        // 不论是哪种情况，都要通知超级管理员
        List<Long> managerIds = userRoleMapper.selectUserIdByRoleName("超级管理员");
        Collection<Long> allUserIds = CollUtil.addAll(userIds, managerIds);
        AlertData alertData = BeanUtil.toBean(deviceData, AlertData.class);
        alertData.setAlertRuleId(rule.getId());
        String alertReason = CharSequenceUtil.format("{}{}{},持续{}个周期就报警", rule.getFunctionName(), rule.getOperator(), rule.getValue(), rule.getDuration());
        alertData.setAlertReason(alertReason);
        alertData.setStatus(0);
        alertData.setType(rule.getAlertDataType());
        allUserIds.forEach(userId -> {
            AlertData dbAlertData = BeanUtil.toBean(alertData, AlertData.class);
            dbAlertData.setUserId(userId);
            dbAlertData.setId(null);
            alertDataService.save(dbAlertData);
            websocketNotity(alertData, rule, allUserIds);
        });


    }


    private void websocketNotity(AlertData alertData, AlertRule rule, Collection<Long> allUserIds) {

        // 属性拷贝
        AlertNotifyVo alertNotifyVo = BeanUtil.toBean(alertData, AlertNotifyVo.class);
        alertNotifyVo.setFunctionName(rule.getFunctionName());
        alertNotifyVo.setAlertDataType(rule.getAlertDataType());
        alertNotifyVo.setNotifyType(1);
        alertNotifyVo.setIsAllConsumer(true);
        // 向指定的人推送消息
        webSocketServer.sendMessageToConsumer(alertNotifyVo, allUserIds);

    }
}
